﻿using gt.rediscache.core.Entry;
using gt.rediscache.core.Utility;
using StackExchange.Redis;
using System;
using System.Threading.Tasks;

namespace gt.rediscache.core.Clients
{
    public partial class RedisClient
    {
        public bool HyperLogLogAdd(string key, string value, StackExchange.Redis.CommandFlags flags = CommandFlags.None)
        {
            var message = new HyperLogLogAddMessage(key, value);
            return Execute(RedisCommand.HyperLogLogAdd, message, flags).BoolResult;
        }

        public bool HyperLogLogAdd(string key, string[] values, StackExchange.Redis.CommandFlags flags = CommandFlags.None)
        {
            var redisValues = RedisValueConverter.Convert(values);
            var message = new HyperLogLogAddArrayMessage(key, redisValues);
            return Execute(RedisCommand.HyperLogLogAddArray, message, flags).BoolResult;
        }

        public long HyperLogLogLength(string key, StackExchange.Redis.CommandFlags flags = CommandFlags.None)
        {
            var message = new HyperLogLogLengthMessage(key);
            return Execute(RedisCommand.HyperLogLogLength, message, flags).LongResult;
        }

        public long HyperLogLogLength(string[] keys, StackExchange.Redis.CommandFlags flags = CommandFlags.None)
        {
            if (this.ClientServerPool.Mode != PoolMode.Single)
                throw new InvalidOperationException("this operation do not support by cluster mode!");
            var redisKeys = RedisValueConverter.ConvertToRedisKeyFromString(keys);
            var message = new HyperLogLogLengthArrayMessage(redisKeys);
            return Execute(RedisCommand.HyperLogLogLengthArray, message, flags).LongResult;
        }

        public void HyperLogLogMerge(string destination, string[] sourceKeys, StackExchange.Redis.CommandFlags flags = CommandFlags.None)
        {
            if (this.ClientServerPool.Mode != PoolMode.Single)
                throw new InvalidOperationException("this operation do not support by cluster mode!");
            var redisKeys = RedisValueConverter.ConvertToRedisKeyFromString(sourceKeys);
            var message = new HyperLogLogMergeArrayMessage(destination, redisKeys);
            Execute(RedisCommand.HyperLogLogMergeArray, message, flags);
        }

        public void HyperLogLogMerge(string destination, string first, string second, StackExchange.Redis.CommandFlags flags = CommandFlags.None)
        {
            if (this.ClientServerPool.Mode != PoolMode.Single)
                throw new InvalidOperationException("this operation do not support by cluster mode!");
            var message = new HyperLogLogMergeMessage(destination, first, second);
            Execute(RedisCommand.HyperLogLogMerge, message, flags);
        }

        #region Async

        public async Task<bool> HyperLogLogAddAsync(string key, string value, StackExchange.Redis.CommandFlags flags = CommandFlags.None)
        {
            var message = new HyperLogLogAddMessage(key, value);
            return await ExecuteAsync(RedisCommand.HyperLogLogAdd, message, flags).ContinueWith(t =>
            {
                return t.Result.BoolResult;
            }).ConfigureAwait(false);
        }

        public async Task<bool> HyperLogLogAddAsync(string key, string[] values, StackExchange.Redis.CommandFlags flags = CommandFlags.None)
        {
            var redisValues = RedisValueConverter.Convert(values);
            var message = new HyperLogLogAddArrayMessage(key, redisValues);
            return await ExecuteAsync(RedisCommand.HyperLogLogAddArray, message, flags).ContinueWith(t =>
            {
                return t.Result.BoolResult;
            }).ConfigureAwait(false);
        }

        public async Task<long> HyperLogLogLengthAsync(string key, StackExchange.Redis.CommandFlags flags = CommandFlags.None)
        {
            var message = new HyperLogLogLengthMessage(key);
            return await ExecuteAsync(RedisCommand.HyperLogLogLength, message, flags).ContinueWith(t =>
            {
                return t.Result.LongResult;
            }).ConfigureAwait(false);
        }

        public async Task<long> HyperLogLogLengthAsync(string[] keys, StackExchange.Redis.CommandFlags flags = CommandFlags.None)
        {
            var redisKeys = RedisValueConverter.ConvertToRedisKeyFromString(keys);
            var message = new HyperLogLogLengthArrayMessage(redisKeys);
            return await ExecuteAsync(RedisCommand.HyperLogLogLengthArray, message, flags).ContinueWith(t =>
            {
                return t.Result.LongResult;
            }).ConfigureAwait(false);
        }

        public async Task HyperLogLogMergeAsync(string destination, string[] sourceKeys, StackExchange.Redis.CommandFlags flags = CommandFlags.None)
        {
            if (this.ClientServerPool.Mode != PoolMode.Single)
                throw new InvalidOperationException("this operation do not support by cluster mode!");
            var redisKeys = RedisValueConverter.ConvertToRedisKeyFromString(sourceKeys);
            var message = new HyperLogLogMergeArrayMessage(destination, redisKeys);
            await ExecuteAsync(RedisCommand.HyperLogLogMergeArray, message, flags).ConfigureAwait(false);
        }

        public async Task HyperLogLogMergeAsync(string destination, string first, string second, StackExchange.Redis.CommandFlags flags = CommandFlags.None)
        {
            if (this.ClientServerPool.Mode != PoolMode.Single)
                throw new InvalidOperationException("this operation do not support by cluster mode!");
            var message = new HyperLogLogMergeMessage(destination, first, second);
            await ExecuteAsync(RedisCommand.HyperLogLogMerge, message, flags).ConfigureAwait(false);
        }

        #endregion

    }
}
